﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using CoreLibrary.Repo;
using Entities.DataBase.Obj;
using Entities.DataBase.Persistent;

namespace Entities.DataBase.Impl {

    public class CustomerRepository : BaseRepository<Customer>, ICustomerRepository{

        private static readonly Func<DataContext, string, Customer>
          LinqGetCustomerById = CompiledQuery.Compile((DataContext context, string customerId)
              => context.GetTable<Customer>().SingleOrDefault(p => p.Id.Equals(customerId)));

        private static readonly Func<DataContext, string, Customer>
         LinqGetCustomerByName = CompiledQuery.Compile((DataContext context, string name)
             => context.GetTable<Customer>().SingleOrDefault(p => p.Name.Equals(name) || p.CName.Equals(name)));

        private static readonly Func<DataContext, string, int, int, IQueryable<Customer>>
           LinqGetCustomers = CompiledQuery.Compile((DataContext context, string keyword, int offset, int limit) =>
                context.GetTable<Customer>()
                       .Where(p => string.Empty.Equals(keyword) || p.Name.Contains(keyword) || p.CName.Contains(keyword) || p.Address1.Contains(keyword) || p.PhoneNumber1.Contains(keyword) || p.Email1.Contains(keyword))
                       .OrderByDescending(p => p.DateCreated)
                       .Skip(offset)
                       .Take(limit)

        );

        private static readonly Func<DataContext, string, IQueryable<Customer>>
           LinqGetCustomersByKeywords = CompiledQuery.Compile((DataContext context, string keyword) =>
                context.GetTable<Customer>()
                       .Where(p => string.Empty.Equals(keyword) || p.Name.Contains(keyword) || p.CName.Contains(keyword) || p.Address1.Contains(keyword) || p.PhoneNumber1.Contains(keyword) || p.Email1.Contains(keyword))
                       .OrderByDescending(p => p.DateCreated)

        );

        public override string TableName {
            get {
                return "D_CUSTOMER";
            }
        }

        public List<Customer> List(string keyword) {
            return Execute(context => LinqGetCustomersByKeywords(context, keyword).ToList());
        }
       
        public Customer Get(string customerId) {
            return Execute(context => LinqGetCustomerById(context, customerId));
        }

        public void Remove(string customerId) {
            Execute((context, ts) => {
                var cus = LinqGetCustomerById(context, customerId);
                if (cus == null) {
                    ts.Complete();
                    return;
                }

                context.GetTable<Customer>().DeleteOnSubmit(cus);
                context.SubmitChanges();
                ts.Complete();
            });
        }

        public void Add(Customer customer) {
            Execute((context, ts) => {
                var cus = LinqGetCustomerById(context, customer.Id);
                if (cus != null) {
                    ts.Complete();
                    throw new Exception("Customer Id already exists.");
                }

                var cusbyName = LinqGetCustomerByName(context,customer.Name);
                if (cusbyName != null) {
                    throw new Exception("Customer Name already exists.");
                }

                var cusbyCName = LinqGetCustomerByName(context, customer.CName);
                if (cusbyCName != null) {
                    throw new Exception("Customer CName already exists.");
                }

                context.GetTable<Customer>().InsertOnSubmit(customer);
                context.SubmitChanges();
                ts.Complete();
            });
        }

        public void Update(CustomerUpdator updator) {
            Execute((context, ts) => {
                var customer = LinqGetCustomerById(context, updator.CustomerId);
                if (customer == null) {
                    ts.Complete();
                    throw new Exception("Customer do not exist.");
                }
                updator.UpdateCustomer(customer);
                context.SubmitChanges();
                ts.Complete();
            });
        }

    }
}